package io.gitee.chearnee.fw.common.utils;

import lombok.experimental.UtilityClass;
import org.springframework.core.MethodParameter;

import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.Optional;

/**
 * @author cn
 * @version 1.0
 * @description
 * @date 11/10/2022 3:54 PM
 */
@UtilityClass
public class AnnotationUtil {

    /**
     * 检查方法上或类上是否有某个注解
     *
     * @param returnType
     * @param targetAnnotations
     * @return
     */
    public static Optional<Annotation> checkOneOfAnnotation(MethodParameter returnType, Collection<Class<?>> targetAnnotations) {
        Executable executable = returnType.getExecutable();
        Optional<Annotation> first = checkOneOfAnnotation(executable, targetAnnotations);
        if (first.isEmpty()) {
            first = checkOneOfAnnotation(executable.getClass(), targetAnnotations);
        }
        return first;
    }

    public static Optional<Annotation> checkOneOfAnnotation(AccessibleObject accessibleObject, Collection<Class<?>> targetAnnotations) {
        return checkOneOfAnnotation(accessibleObject.getAnnotations(), targetAnnotations);
    }

    public static Optional<Annotation> checkOneOfAnnotation(Class<?> cls, Collection<Class<?>> targetAnnotations) {
        return checkOneOfAnnotation(cls.getAnnotations(), targetAnnotations);
    }

    public static Optional<Annotation> checkOneOfAnnotation(Field field, Collection<Class<?>> targetAnnotations) {
        return checkOneOfAnnotation(field.getAnnotations(), targetAnnotations);
    }

    /**
     * 检测是否包含某注解
     *
     * @param annotations
     * @param targetAnnotations
     * @return
     */
    public static Optional<Annotation> checkOneOfAnnotation(Annotation[] annotations, Collection<Class<?>> targetAnnotations) {
        if (targetAnnotations == null || annotations == null) {
            return Optional.empty();
        }
        return Arrays.stream(annotations).filter(e -> {
            for (Class<?> targetAnnotation : targetAnnotations) {
                if (targetAnnotation == null) {
                    return false;
                }
                if (targetAnnotation.isAssignableFrom(e.annotationType())) {
                    return true;
                }
            }
            return false;
        }).findFirst();
    }
}
